home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 25 / CU Amiga Magazine's Super CD-ROM 25 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-08].iso / CUCD / Programming / QuakeTools / src / libqtools / TDDD.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-11  |  35.4 KB  |  1,149 lines

  1. #define    LIBQTOOLS_CORE
  2. #include "../include/libqtools.h"
  3. #include "../include/libqbuild.h"
  4. #include "TDDD.h"
  5.  
  6. #define    CLUSTER_POINTS        (CLUSTER_FACES / 3)
  7. #define    CLUSTER_GROUPS        16
  8. #define    CLUSTER_SUBGROUP    (CLUSTER_FACES / 3)
  9.  
  10. int TDDDmax_pcount = 0;
  11. int TDDDmax_ecount = 0;
  12. int TDDDmax_tcount = 0;
  13. int TDDDmax_gcount = 0;
  14. struct points *TDDDpoints = 0;
  15. struct edges *TDDDedges = 0;
  16. struct faces *TDDDfaces = 0;
  17. int TDDDgroups = 0;
  18. int *TDDDgroupsizes = 0;
  19. struct facesubgroup **TDDDgroup = 0;
  20. struct brush5 *TDDDbrushes = 0;
  21.  
  22. int TDDDnumpoints = 0;
  23. int TDDDnumedges = 0;
  24. int TDDDnumfaces = 0;
  25. int TDDDnumgroups = 0;
  26. int TDDDnumobjects = 0;
  27.  
  28. int nummapbrushes;                               // 4
  29.  
  30. void AllocTDDDSubGroup(register int faceNum, register char *texname)
  31. {
  32.   unsigned short int i, j;
  33.  
  34.   if (!TDDDgroup) {
  35.     if (!(TDDDgroup = (struct facesubgroup **)tmalloc(CLUSTER_GROUPS * sizeof(struct facesubgroup *))))
  36.         Error("AllocGroup: failed to allocate group!\n");
  37.     if (!(TDDDgroupsizes = (int *)tmalloc(CLUSTER_GROUPS * sizeof(int))))
  38.         Error("AllocGroup: failed to allocate group!\n");
  39.     if (!(TDDDbrushes = (struct brush5 *)tmalloc(CLUSTER_GROUPS * sizeof(struct brush5))))
  40.         Error("AllocGroups: failed to allocate brush!\n");
  41.   }
  42.  
  43.   if (TDDDgroups >= TDDDmax_gcount) {
  44.     if (!(TDDDgroup = (struct facesubgroup **)trealloc(TDDDgroup, ((TDDDmax_gcount += CLUSTER_GROUPS) * sizeof(struct facesubgroup *)))))
  45.       Error("AllocGroup: failed to reallocate group!\n");
  46.     if (!(TDDDgroupsizes = (int *)trealloc(TDDDgroupsizes, (TDDDmax_gcount * sizeof(int)))))
  47.       Error("AllocGroup: failed to reallocate group!\n");
  48.     if (!(TDDDbrushes = (struct brush5 *)trealloc(TDDDbrushes, (TDDDmax_gcount * sizeof(struct brush5)))))
  49.       Error("AllocGroup: failed to reallocate brush!\n");
  50.   }
  51.  
  52.   for (i = 0; i < TDDDgroups; i++)
  53.     if(!strncmp(TDDDgroup[i]->name, texname, 18))
  54.       break;
  55.  
  56.   if (!TDDDgroup[i])
  57.     if (!(TDDDgroup[i] = (struct facesubgroup *)tmalloc((CLUSTER_SUBGROUP * sizeof(unsigned short int)) + sizeof(struct facesubgroup))))
  58.       Error("AllocGroup: failed to allocate subgroup!\n");
  59.   
  60.   if (TDDDgroup[i]->count >= TDDDgroupsizes[i])
  61.     if (!(TDDDgroup[i] = (struct facesubgroup *)trealloc(TDDDgroup[i], ((TDDDgroupsizes[i] += CLUSTER_SUBGROUP) * sizeof(unsigned short int)) + sizeof(struct facesubgroup))))
  62.       Error("AllocGroup: failed to reallocate subgroup!\n");
  63.   
  64.   if (i == TDDDgroups) {
  65.     strncpy(TDDDgroup[i]->name, texname, 18);
  66.     TDDDbrushes[i].fullscale = 1;
  67.     TDDDbrushes[i].flags = BRS_COLOR;
  68.     TDDDbrushes[i].wflags = BRW_REPEA;
  69.     TDDDgroups++;
  70.     TDDDnumgroups++;
  71.   }
  72.   
  73.   for (j = 0; j < TDDDgroup[i]->count; j++)
  74.     if (faceNum == TDDDgroup[i]->facelist[j])
  75.       return;
  76.  
  77.   TDDDgroup[i]->facelist[j] = faceNum;
  78.   TDDDgroup[i]->count++;
  79. }
  80.  
  81. unsigned short int AllocTDDDPoint(register vector * point)
  82. {
  83.   unsigned short int i;
  84.  
  85.   if (!TDDDpoints)
  86.     if (!(TDDDpoints = (struct points *)tmalloc((CLUSTER_POINTS * sizeof(vector)) + sizeof(struct points))))
  87.         Error("AllocPoint: failed to allocate point!\n");
  88.  
  89.   if (TDDDpoints->pcount >= TDDDmax_pcount)
  90.     if (!(TDDDpoints = (struct points *)trealloc(TDDDpoints, ((TDDDmax_pcount += CLUSTER_POINTS) * sizeof(vector)) + sizeof(struct points))))
  91.         Error("AllocPoint: failed to reallocate point!\n");
  92.  
  93.   for (i = 0; i < TDDDpoints->pcount; i++) {
  94.     if (point->x == TDDDpoints->points[i].x)
  95.       if (point->y == TDDDpoints->points[i].y)
  96.     if (point->z == TDDDpoints->points[i].z)
  97.           return i;
  98.   }
  99.   TDDDpoints->points[i].x = point->x;
  100.   TDDDpoints->points[i].y = point->y;
  101.   TDDDpoints->points[i].z = point->z;
  102.   TDDDpoints->pcount++;
  103.   TDDDnumpoints++;
  104.   return i;
  105. }
  106.  
  107. unsigned short int AllocTDDDEdge(register unsigned short int point0, register unsigned short int point1)
  108. {
  109.   unsigned short int i;
  110.  
  111.   if (!TDDDedges)
  112.     if (!(TDDDedges = (struct edges *)tmalloc((CLUSTER_EDGES * sizeof(unsigned short int) * 2) + sizeof(struct edges))))
  113.         Error("AllocEdge: failed to allocate edge!\n");
  114.  
  115.   if (TDDDedges->ecount >= TDDDmax_ecount)
  116.     if (!(TDDDedges = (struct edges *)trealloc(TDDDedges, ((TDDDmax_ecount += CLUSTER_EDGES) * sizeof(unsigned short int) * 2) + sizeof(struct edges))))
  117.         Error("AllocEdge: failed to reallocate edge!\n");
  118.  
  119.   for (i = 0; i < TDDDedges->ecount; i++) {
  120.     if (point0 == TDDDedges->edges[i][0])
  121.       if (point1 == TDDDedges->edges[i][1])
  122.         return i;
  123.   }
  124.   TDDDedges->edges[i][0] = point0;
  125.   TDDDedges->edges[i][1] = point1;
  126.   TDDDedges->ecount++;
  127.   TDDDnumedges++;
  128.   return i;
  129. }
  130.  
  131. unsigned short int AllocTDDDFace(register unsigned short int connect0, register unsigned short int connect1, register unsigned short int connect2)
  132. {
  133.   unsigned short int i;
  134.  
  135.   if (!TDDDfaces)
  136.     if (!(TDDDfaces = (struct faces *)tmalloc((CLUSTER_FACES * sizeof(unsigned short int) * 3) + sizeof(struct faces))))
  137.         Error("AllocFace: failed to allocate face!\n");
  138.  
  139.   if (TDDDfaces->tcount >= TDDDmax_tcount)
  140.     if (!(TDDDfaces = (struct faces *)trealloc(TDDDfaces, ((TDDDmax_tcount += CLUSTER_FACES) * sizeof(unsigned short int) * 3) + sizeof(struct faces))))
  141.         Error("AllocFace: failed to reallocate face!\n");
  142.  
  143.   for (i = 0; i < TDDDfaces->tcount; i++) {
  144.     if (connect0 == TDDDfaces->connects[i][0])
  145.       if (connect1 == TDDDfaces->connects[i][1])
  146.     if (connect2 == TDDDfaces->connects[i][2])
  147.           return i;
  148.   }
  149.   TDDDfaces->connects[i][0] = connect0;
  150.   TDDDfaces->connects[i][1] = connect1;
  151.   TDDDfaces->connects[i][2] = connect2;
  152.   TDDDfaces->tcount++;
  153.   TDDDnumfaces++;
  154.   return i;
  155. }
  156.  
  157. bool SaveFace(vec3_t point0, vec3_t point1, vec3_t point2, register char *texname)
  158. {
  159.   unsigned short int face, p0, p1, p2;
  160.   vector p;
  161.  
  162.   p.x = float2fract(point0[0]);
  163.   p.y = float2fract(point0[1]);
  164.   p.z = float2fract(point0[2]);
  165.   p0 = AllocTDDDPoint(&p);
  166.   p.x = float2fract(point1[0]);
  167.   p.y = float2fract(point1[1]);
  168.   p.z = float2fract(point1[2]);
  169.   p1 = AllocTDDDPoint(&p);
  170.   p.x = float2fract(point2[0]);
  171.   p.y = float2fract(point2[1]);
  172.   p.z = float2fract(point2[2]);
  173.   p2 = AllocTDDDPoint(&p);
  174.  
  175.   face = AllocTDDDFace(AllocTDDDEdge(p0, p1),
  176.                AllocTDDDEdge(p1, p2),
  177.                AllocTDDDEdge(p2, p0));
  178.   AllocTDDDSubGroup(face, texname);
  179.   return TRUE;
  180. }
  181.  
  182. bool SetForm(register FILE * outFile, register int *last, register char *ID)
  183. {
  184.   fwrite("FORM", 1, 4, outFile);
  185.   fwrite(last, 1, 4, outFile);
  186.   *last = ftell(outFile);
  187.   fwrite(ID, 1, 4, outFile);
  188.  
  189.   return TRUE;
  190. }
  191.  
  192. bool SetRoot(register FILE * outFile, register int *last, register char *ID)
  193. {
  194.   fwrite(ID, 1, 4, outFile);
  195.   fwrite(last, 1, 4, outFile);
  196.   *last = ftell(outFile);
  197.  
  198.   return TRUE;
  199. }
  200.  
  201. bool SetEndM(register FILE * outFile, register char *ID)
  202. {
  203.   int len = 0;
  204.  
  205.   fwrite(ID, 1, 4, outFile);
  206.   fwrite(&len, 1, 4, outFile);
  207.   TDDDnumobjects++;
  208.  
  209.   return TRUE;
  210. }
  211.  
  212. bool VerRoot(register FILE * outFile, register int *last, register char *ID)
  213. {
  214.   int this = ftell(outFile);
  215.  
  216.   fseek(outFile, *last - 8, SEEK_SET);
  217.   *last = this - *last;
  218.   fwrite(ID, 1, 4, outFile);
  219.   fwrite(last, 1, 4, outFile);
  220.   fseek(outFile, this, SEEK_SET);
  221.  
  222.   return TRUE;
  223. }
  224.  
  225. bool SetClassName(register FILE * outFile, register char *className)
  226. {
  227.   int len = 18;
  228.  
  229.   fwrite("NAME", 1, 4, outFile);
  230.   fwrite(&len, 1, 4, outFile);
  231.   fwrite(className, 1, len, outFile);
  232.  
  233.   return TRUE;
  234. }
  235.  
  236. bool SetEntity(register FILE * outFile, register char *variable, register char *content)
  237. {
  238.   int len = sizeof(struct texture4);
  239.   int nameLen = strlen(content);
  240.   struct texture4 brushTex;
  241.   
  242.   nameLen = ((nameLen + 1) & ~1);
  243.   nameLen++;
  244.   nameLen = ((nameLen + 1) & ~1);
  245.   memset(&brushTex, 0, len);
  246.   strncpy(brushTex.label, variable, 18 + 1);
  247.   brushTex.flags = TXT_DISAB;
  248.   len += brushTex.length = nameLen;
  249.   fwrite("TXT4", 1, 4, outFile);
  250.   fwrite(&len, 1, 4, outFile);
  251.   fwrite(&brushTex, 1, len - nameLen, outFile);
  252.   fwrite(content, 1, nameLen - 1, outFile);
  253.   fwrite("\0", 1, 1, outFile);
  254.  
  255.   return TRUE;
  256. }
  257.  
  258. bool SetBrushes(register FILE * outFile)
  259. {
  260.   int lastBrush, i;
  261.   
  262.   for(i = 0; i < TDDDgroups; i++) {
  263.     /*
  264.      * write only a subgroup if there are more than one
  265.      * and if the subgroup contains members
  266.      */
  267.     if((TDDDgroups > 1) && (TDDDgroup[i]->count > 0)) {
  268.       SetRoot(outFile, &lastBrush, "FGRP");
  269.       fwrite(TDDDgroup[i], 1, 20 + (sizeof(unsigned short int) * TDDDgroup[i]->count), outFile);
  270.       VerRoot(outFile, &lastBrush, "FGRP");
  271.       strncpy(TDDDbrushes[i].subgrp, TDDDgroup[i]->name, 18);
  272.     }
  273.     SetRoot(outFile, &lastBrush, "BRS5");
  274.     TDDDbrushes[i].length = ((strlen(TDDDgroup[i]->name + 1) + 1) & ~1);
  275.     fwrite(&TDDDbrushes[i], 1, sizeof(struct brush5), outFile);
  276.     fwrite(TDDDgroup[i]->name, 1, TDDDbrushes[i].length, outFile);
  277.     VerRoot(outFile, &lastBrush, "BRS5");
  278.     TDDDgroup[i]->count = 0;
  279.   }
  280.   TDDDgroups = 0;
  281.  
  282.   return TRUE;
  283. }
  284.  
  285. bool SetPoints(register FILE * outFile)
  286. {
  287.   if(TDDDpoints) {
  288.     if(TDDDpoints->pcount) {
  289.       int len = (sizeof(vector) * TDDDpoints->pcount) + sizeof(unsigned short int);
  290.  
  291.       fwrite("PNTS", 1, 4, outFile);
  292.       fwrite(&len, 1, 4, outFile);
  293.       fwrite(TDDDpoints, 1, len, outFile);
  294.  
  295.       TDDDpoints->pcount = 0;
  296.     }
  297.   }
  298.   return TRUE;
  299. }
  300.  
  301. bool SetEdges(register FILE * outFile)
  302. {
  303.   if(TDDDedges) {
  304.     if(TDDDedges->ecount) {
  305.       int len = sizeof(unsigned short int) * ((TDDDedges->ecount * 2) + 1);
  306.  
  307.       fwrite("EDGE", 1, 4, outFile);
  308.       fwrite(&len, 1, 4, outFile);
  309.       fwrite(TDDDedges, 1, len, outFile);
  310.  
  311.       TDDDedges->ecount = 0;
  312.     }
  313.   }
  314.   return TRUE;
  315. }
  316.  
  317. bool SetFaces(register FILE * outFile)
  318. {
  319.   if(TDDDfaces) {
  320.     if(TDDDfaces->tcount) {
  321.       int len = sizeof(unsigned short int) * ((TDDDfaces->tcount * 3) + 1);
  322.  
  323.       fwrite("FACE", 1, 4, outFile);
  324.       fwrite(&len, 1, 4, outFile);
  325.       fwrite(TDDDfaces, 1, len, outFile);
  326.  
  327.       TDDDfaces->tcount = 0;
  328.     }
  329.   }
  330.   return TRUE;
  331. }
  332.  
  333. bool SetOtherDefaults(register FILE * outFile, register struct entity *ent)
  334. {
  335.   double posx = 0;
  336.   double posy = 0;
  337.   double posz = 0;
  338.   int points, len, i;
  339.   struct axis axis = {{0x00010000, 0x00000000, 0x00000000},
  340.               {0x00000000, 0x00010000, 0x00000000},
  341.               {0x00000000, 0x00000000, 0x00010000}};
  342.   struct posi position = {{0, 0, 0}};
  343.   struct shap shape = {SH_AXIS, LP2_NOLAM};
  344.   struct colr colour;
  345.  
  346.   if(ent) {
  347.     position.position.x = float2fract(ent->origin[0]);
  348.     position.position.y = float2fract(ent->origin[1]);
  349.     position.position.z = float2fract(ent->origin[2]);
  350.     if(ent->style) {
  351.       struct int1 light;
  352.       
  353.       shape.lamp = LP2_POINT;
  354.       
  355.       light.intensity.x = light.intensity.y = light.intensity.z = ((unsigned int)ent->light << 22) / 75;
  356.       len = sizeof(struct int1);
  357.       fwrite("INT1", 1, 4, outFile);
  358.       fwrite(&len, 1, 4, outFile);
  359.       fwrite(&light, 1, len, outFile);
  360.     }
  361.   }
  362.  
  363.   if(TDDDpoints)
  364.   if(TDDDpoints->pcount) {
  365.     struct bbox bound = {{0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF}, {0x8000000, 0x80000000, 0x80000000}};
  366.     struct faceattr *attr = (struct faceattr *)tmalloc((TDDDfaces->tcount * sizeof(rgb)) + sizeof(struct faceattr));
  367.     
  368.     for (points = 0; points < TDDDpoints->pcount; points++) {
  369.       if(TDDDpoints->points[points].x > bound.maxs.x)
  370.         bound.maxs.x = TDDDpoints->points[points].x;
  371.       else if(TDDDpoints->points[points].x < bound.mins.x)
  372.         bound.mins.x = TDDDpoints->points[points].x;
  373.       if(TDDDpoints->points[points].y > bound.maxs.y)
  374.         bound.maxs.y = TDDDpoints->points[points].y;
  375.       else if(TDDDpoints->points[points].y < bound.mins.y)
  376.         bound.mins.y = TDDDpoints->points[points].y;
  377.       if(TDDDpoints->points[points].z > bound.maxs.z)
  378.         bound.maxs.z = TDDDpoints->points[points].z;
  379.       else if(TDDDpoints->points[points].z < bound.mins.z)
  380.         bound.mins.z = TDDDpoints->points[points].z;
  381.       posx += fract2float(TDDDpoints->points[points].x);
  382.       posy += fract2float(TDDDpoints->points[points].y);
  383.       posz += fract2float(TDDDpoints->points[points].z);
  384.     }
  385.     position.position.x = float2fract(posx / TDDDpoints->pcount);
  386.     position.position.y = float2fract(posy / TDDDpoints->pcount);
  387.     position.position.z = float2fract(posz / TDDDpoints->pcount);
  388.     
  389.     bound.maxs.x -= position.position.x;
  390.     bound.maxs.y -= position.position.y;
  391.     bound.maxs.z -= position.position.z;
  392.     bound.mins.x -= position.position.x;
  393.     bound.mins.y -= position.position.y;
  394.     bound.mins.z -= position.position.z;
  395.     len = sizeof(struct bbox);
  396.     fwrite("BBOX", 1, 4, outFile);
  397.     fwrite(&len, 1, 4, outFile);
  398.     fwrite(&bound, 1, len, outFile);
  399.     
  400.     attr->count = TDDDfaces->tcount;
  401.     for (i = 0; i < TDDDfaces->tcount; i++) {
  402.       attr->attr[i].r = 0xFF;
  403.       attr->attr[i].g = 0xFF;
  404.       attr->attr[i].b = 0xFF;
  405.     }
  406.     len = (TDDDfaces->tcount * sizeof(rgb)) + sizeof(unsigned short int);
  407.     len = ((len + 1) & ~1);
  408.     fwrite("CLST", 1, 4, outFile);
  409.     fwrite(&len, 1, 4, outFile);
  410.     fwrite(&attr, 1, len, outFile);
  411.     fwrite("RLST", 1, 4, outFile);
  412.     fwrite(&len, 1, 4, outFile);
  413.     fwrite(&attr, 1, len, outFile);
  414.     fwrite("TLST", 1, 4, outFile);
  415.     fwrite(&len, 1, 4, outFile);
  416.     fwrite(&attr, 1, len, outFile);
  417.  
  418.     tfree(attr);
  419.   }
  420.  
  421.   len = sizeof(struct axis);
  422.   fwrite("AXIS", 1, 4, outFile);
  423.   fwrite(&len, 1, 4, outFile);
  424.   fwrite(&axis, 1, len, outFile);
  425.  
  426.   len = sizeof(struct posi);
  427.   fwrite("POSI", 1, 4, outFile);
  428.   fwrite(&len, 1, 4, outFile);
  429.   fwrite(&position, 1, len, outFile);
  430.  
  431.   len = sizeof(struct shap);
  432.   fwrite("SHP2", 1, 4, outFile);
  433.   fwrite(&len, 1, 4, outFile);
  434.   fwrite(&shape, 1, len, outFile);
  435.  
  436.   colour.color = 0x00FFFFFF;
  437.   len = sizeof(struct colr);
  438.   fwrite("COLR", 1, 4, outFile);
  439.   fwrite(&len, 1, 4, outFile);
  440.   fwrite(&colour, 1, len, outFile);
  441.   fwrite("REFL", 1, 4, outFile);
  442.   fwrite(&len, 1, 4, outFile);
  443.   fwrite(&colour, 1, len, outFile);
  444.   fwrite("TRAN", 1, 4, outFile);
  445.   fwrite(&len, 1, 4, outFile);
  446.   fwrite(&colour, 1, len, outFile);
  447.   fwrite("SPC1", 1, 4, outFile);
  448.   fwrite(&len, 1, 4, outFile);
  449.   fwrite(&colour, 1, len, outFile);
  450.  
  451.   return TRUE;
  452. }
  453.  
  454. /*
  455.  * convert a Imagine-TDDD to a Quake-Map
  456.  */
  457.  
  458. /* IFF to pseudo IFF */
  459. int fileIFFtopIFF(FILE *iobFile, struct IFFchunk *IFFroot);
  460. int memIFFtopIFF(char *iobMem, struct IFFchunk *IFFroot);
  461. /* pseudo IFF to pseudo Brushes */
  462. void pIFFtopBrushes(__memBase, struct IFFchunk *IFFroot, int iterVal, struct entity *fillEntity);
  463. /* pseudo IFF to pseudo Map */
  464. void pIFFtopMap(__memBase, struct IFFchunk *IFFroot, int iterVal);
  465.  
  466. void strlwrcpy(register char *dst, register char *src) {
  467.   int i, len = strlen(src);
  468.   for (i = 0; i < len; i++)
  469.     dst[i] = (char)tolower((int)src[i]);
  470.   dst[i] = 0;
  471. }
  472.  
  473. int fileIFFtopIFF(register FILE *iobFile, register struct IFFchunk *IFFroot) {
  474.   int processed = 0;
  475.   /*
  476.    * small hack -> IFFroot->iter is IFFpart->next
  477.    */
  478.   struct IFFchunk *IFFpart = (struct IFFchunk *)&IFFroot->size;
  479.  
  480.   while (IFFpart->type != ID_TOBJ) {
  481.     int oldOffs;
  482.     
  483.     /*
  484.      * allocate IFFchunk
  485.      */
  486.     IFFpart->next = (struct IFFchunk *)tmalloc(sizeof(struct IFFchunk));
  487.     IFFpart = IFFpart->next;
  488.     IFFpart->next = 0;
  489.     IFFpart->iter = 0;
  490.     IFFpart->data = 0;
  491.     
  492.     /*
  493.      * read and parse IFFchunk
  494.      */
  495.     fread(IFFpart, 1, 8, iobFile);
  496.     IFFpart->size += 0x00000001;
  497.     IFFpart->size &= 0xFFFFFFFE;
  498.     processed += 8;
  499.     oldOffs = ftell(iobFile);
  500.  
  501.     if(IFFpart->type == ID_OBJ) {
  502.       processed += fileIFFtopIFF(iobFile, IFFpart);
  503.       if((IFFroot->type == ID_TDDD) && (IFFroot->size == processed))
  504.         break;
  505.     }
  506.     else if(IFFpart->type == ID_DESC) {
  507.       processed += fileIFFtopIFF(iobFile, IFFpart);
  508.       if((IFFroot->type == ID_OBJ) && (IFFroot->size == processed))
  509.         break;
  510.     }
  511.     else if(IFFpart->type != ID_TOBJ) {
  512.       processed += IFFpart->size;
  513.       IFFpart->data = (void *)tmalloc(IFFpart->size + 1);
  514.       fread(IFFpart->data, 1, IFFpart->size, iobFile);
  515.     }
  516.   }
  517.   
  518.   return processed;
  519. }
  520.  
  521. int memIFFtopIFF(register char *iobMem, register struct IFFchunk *IFFroot) {
  522.   int processed = 0;
  523.   /*
  524.    * small hack -> IFFroot->iter is IFFpart->next
  525.    */
  526.   struct IFFchunk *IFFpart = (struct IFFchunk *)&IFFroot->size;
  527.  
  528.   while (IFFpart->type != ID_TOBJ) {
  529.     /*
  530.      * allocate IFFchunk
  531.      */
  532.     IFFpart->next = (struct IFFchunk *)tmalloc(sizeof(struct IFFchunk));
  533.     IFFpart = IFFpart->next;
  534.     IFFpart->next = 0;
  535.     IFFpart->iter = 0;
  536.     IFFpart->data = 0;
  537.     
  538.     /*
  539.      * read and parse IFFchunk
  540.      */
  541.     memcpy(IFFpart, iobMem, 8);
  542.     iobMem += 8;
  543.     IFFpart->size += 0x00000001;
  544.     IFFpart->size &= 0xFFFFFFFE;
  545.     processed += 8;
  546.  
  547.     if(IFFpart->type == ID_OBJ) {
  548.       processed += memIFFtopIFF(iobMem, IFFpart);
  549.       if((IFFroot->type == ID_TDDD) && (IFFroot->size == processed))
  550.         break;
  551.     }
  552.     else if(IFFpart->type == ID_DESC) {
  553.       processed += memIFFtopIFF(iobMem, IFFpart);
  554.       if((IFFroot->type == ID_OBJ) && (IFFroot->size == processed))
  555.         break;
  556.     }
  557.     else if(IFFpart->type != ID_TOBJ) {
  558.       processed += IFFpart->size;
  559.       IFFpart->data = (void *)tmalloc(IFFpart->size + 1);
  560.       memcpy(IFFpart->data, iobMem, IFFpart->size);
  561.       iobMem += IFFpart->size;
  562.     }
  563.   }
  564.   
  565.   return processed;
  566. }
  567.  
  568. void pIFFtopBrushes(__memBase, register struct IFFchunk *IFFroot, register int iterVal, register struct entity *fillEntity) {
  569.   struct IFFchunk *IFFpart = IFFroot;
  570.  
  571.   struct faces *facelist = 0;
  572.   struct posi *origin = 0;
  573.   struct edges *edgelist = 0;
  574.   struct points *pointlist = 0;
  575.   struct brush5 **brushtex = (struct brush5 **)tmalloc(15 * sizeof(struct brush5 *));
  576.   int brushtexs = 0;
  577.   struct facesubgroup **facegroup = (struct facesubgroup **)tmalloc(15 * sizeof(struct facesubgroup *));
  578.   int facegroups = 0;
  579.  
  580.   /*
  581.    * look for other iterated brushes
  582.    */
  583.   while (IFFpart) {
  584.     struct IFFchunk *actIFFpart = IFFpart;
  585.     int indentSpace = iterVal;
  586.     
  587.     while (indentSpace-- > 0) {
  588.       oprintf("  ");
  589.     }
  590.     oprintf("%4s %d bytes\n", (char *)&IFFpart->type, IFFpart->size);
  591.     
  592.     /*
  593.      * all types that are not DESC are for the actBrush
  594.      * after first appeareance of DESC there are only DESCs
  595.      */
  596.     switch (IFFpart->type) {
  597.       case ID_POSI:
  598.         origin = (struct posi *)actIFFpart->data;
  599.         break;
  600.       case ID_FACE:
  601.         facelist = (struct faces *)actIFFpart->data;
  602.         break;
  603.       case ID_EDGE:
  604.         edgelist = (struct edges *)actIFFpart->data;
  605.         break;
  606.       case ID_PNTS:
  607.         pointlist = (struct points *)actIFFpart->data;
  608.         break;
  609.       case ID_FGRP:
  610.       case ID_FGR2:
  611.       case ID_FGR3:
  612.       case ID_FGR4:
  613.         facegroup[facegroups] = (struct facesubgroup *)actIFFpart->data;
  614.         facegroups++;
  615.         break;
  616.       case ID_BRS5:
  617.         brushtex[brushtexs] = (struct brush5 *)actIFFpart->data;
  618.         brushtexs++;
  619.         break;
  620.       case ID_DESC:
  621.         pIFFtopBrushes(bspMem, actIFFpart->iter, iterVal + 1, fillEntity);
  622.         break;
  623.       default:
  624.         tfree(actIFFpart->data);
  625.         break;
  626.     }
  627.     IFFpart = IFFpart->next;
  628.     tfree(actIFFpart);
  629.   }
  630.   
  631.   if(facelist && edgelist && pointlist && brushtexs) {
  632.     int i;
  633.   
  634.     unsigned short int facecnt;
  635.     struct mbrush *actBrush = (struct mbrush *)tmalloc(sizeof(struct mbrush));
  636.     struct mface *checkFace = 0;
  637.     vec3_t middle;
  638.     unsigned short int p0, p1, p2;
  639.     vector *point;
  640.     
  641.     for (facecnt = 0; facecnt < facelist->tcount; facecnt++) {
  642.       p0 = edgelist->edges[facelist->connects[facecnt][0]][0];
  643.       p1 = edgelist->edges[facelist->connects[facecnt][0]][1];
  644.       if((edgelist->edges[facelist->connects[facecnt][1]][0] != p0) &&
  645.          (edgelist->edges[facelist->connects[facecnt][1]][0] != p1))
  646.          p2 = edgelist->edges[facelist->connects[facecnt][1]][0];
  647.       else
  648.          p2 = edgelist->edges[facelist->connects[facecnt][1]][1];
  649.     
  650.       point = &pointlist->points[p0];
  651.       middle[0] += fract2float(point->x);
  652.       middle[1] += fract2float(point->y);
  653.       middle[2] += fract2float(point->z);
  654.       point = &pointlist->points[p1];
  655.       middle[0] += fract2float(point->x);
  656.       middle[1] += fract2float(point->y);
  657.       middle[2] += fract2float(point->z);
  658.       point = &pointlist->points[p2];
  659.       middle[0] += fract2float(point->x);
  660.       middle[1] += fract2float(point->y);
  661.       middle[2] += fract2float(point->z);
  662.     }
  663.     middle[0] /= (facecnt * 3);
  664.     middle[1] /= (facecnt * 3);
  665.     middle[2] /= (facecnt * 3);
  666.       
  667.     for (facecnt = 0; facecnt < facelist->tcount; facecnt++) {
  668.       int j;
  669.       struct mface *actFace = (struct mface *)tmalloc(sizeof(struct mface));
  670.       vec3_t t1, t2, t3;
  671.       float distance;
  672.       
  673.       p0 = edgelist->edges[facelist->connects[facecnt][0]][0];
  674.       p1 = edgelist->edges[facelist->connects[facecnt][0]][1];
  675.       if((edgelist->edges[facelist->connects[facecnt][1]][0] != p0) &&
  676.          (edgelist->edges[facelist->connects[facecnt][1]][0] != p1))
  677.          p2 = edgelist->edges[facelist->connects[facecnt][1]][0];
  678.       else
  679.          p2 = edgelist->edges[facelist->connects[facecnt][1]][1];
  680.       
  681.       point = &pointlist->points[p0];
  682.       actFace->p0[0] = fract2float(point->x);
  683.       actFace->p0[1] = fract2float(point->y);
  684.       actFace->p0[2] = fract2float(point->z);
  685.       point = &pointlist->points[p1];
  686.       actFace->p1[0] = fract2float(point->x);
  687.       actFace->p1[1] = fract2float(point->y);
  688.       actFace->p1[2] = fract2float(point->z);
  689.       point = &pointlist->points[p2];
  690.       actFace->p2[0] = fract2float(point->x);
  691.       actFace->p2[1] = fract2float(point->y);
  692.       actFace->p2[2] = fract2float(point->z);
  693.  
  694.       /*
  695.        * correct to clockwise order
  696.        * planenormal must direct to other side of middle
  697.        * or: the middle must be in the negative side of the room splitted by the plane
  698.        * positive distance between plane and point mean it is on the positive side
  699.        *
  700.        * Erzeugen der Hessischen Normalenform
  701.        * building of hesse-normalform ? to calculate distane between plane and point
  702.        */
  703.       VectorSubtract(actFace->p0, actFace->p1, t1);
  704.       VectorSubtract(actFace->p2, actFace->p1, t2);
  705.       VectorCopy(actFace->p1, t3);
  706.       CrossProduct(t1, t2, actFace->plane.normal);
  707.       VectorNormalize(actFace->plane.normal);
  708.       actFace->plane.dist = DotProduct(t3, actFace->plane.normal);
  709.       
  710.       if((distance = DotProduct(middle, actFace->plane.normal) - actFace->plane.dist) > 0) {
  711.         vec3_t temp;
  712.         
  713.         VectorCopy(actFace->p0, temp);
  714.         VectorCopy(actFace->p2, actFace->p0);
  715.         VectorCopy(temp, actFace->p2);
  716.       
  717.         VectorNegate(actFace->plane.normal);
  718.         actFace->plane.dist = -actFace->plane.dist;
  719.       }
  720.  
  721.       /*
  722.        * elimination doubled faces in resulting only valid brushes
  723.        * equal is: if normal and distance to origin are equal
  724.        * the distance to origin is equal then if the angle between normal and normal of ?-normal is equal
  725.        *
  726.        * in theory in quakeMode, there are no eleminations possible
  727.        */
  728.       checkFace = actBrush->faces;
  729.       while(checkFace) {
  730.         float a, b, c;
  731.         /* Abstand Punkt->Ebene / distances point->plane */
  732.         a = fabs(DotProduct(actFace->p0, checkFace->plane.normal) - checkFace->plane.dist);
  733.         b = fabs(DotProduct(actFace->p1, checkFace->plane.normal) - checkFace->plane.dist);
  734.         c = fabs(DotProduct(actFace->p2, checkFace->plane.normal) - checkFace->plane.dist);
  735.         
  736.         /* if point->plane less than minimum, eleminate them */
  737.         if ((a < ON_EPSILON) && (b < ON_EPSILON) && (c < ON_EPSILON))
  738.       break;
  739.  
  740.         checkFace = checkFace->next;
  741.       }
  742.       
  743.       if(!checkFace) {
  744.     /*
  745.      * get the textures
  746.      */
  747.         for(i = 0; i < facegroups; i++) {
  748.           for(j = 0; j < facegroup[i]->count; j++) {
  749.             if(facegroup[i]->facelist[j] == facecnt)
  750.               break;
  751.           }
  752.           if(j < facegroup[i]->count)
  753.             break;
  754.         }
  755.         for(j = 0; j < brushtexs; j++) {
  756.           if(!strncmp(facegroup[i]->name, brushtex[j]->subgrp, 18))
  757.             break;
  758.         }
  759.         if(j < brushtexs) {
  760.           float zero[2] = {0, 0};
  761.           float one[2] = {1, 1};
  762.           actFace->texinfo = MakeTexinfo(bspMem, brushtex[j]->name, actFace, one, 0, zero);
  763.         }
  764.       
  765.         actFace->next = actBrush->faces;
  766.         actBrush->faces = actFace;
  767.       }
  768.       else
  769.         tfree(actFace);
  770.     }
  771.     
  772.     tfree(facelist);
  773.     tfree(edgelist);
  774.     tfree(pointlist);
  775.     for(i = 0; i < facegroups; i++)
  776.       tfree(facegroup[i]);
  777.     tfree(facegroup);
  778.     for(i = 0; i < brushtexs; i++)
  779.       tfree(brushtex[i]);
  780.     tfree(brushtex);
  781.     
  782.     /*
  783.      * put in brush
  784.      */
  785.     actBrush->next = fillEntity->brushes;
  786.     fillEntity->brushes = actBrush;
  787.     nummapbrushes++;
  788.   }
  789.   else
  790.     eprintf("not enough data to convert brush!\n");
  791. }
  792.  
  793. void pIFFtopMap(__memBase, register struct IFFchunk *IFFroot, register int iterVal) {
  794.   struct IFFchunk *IFFpart = IFFroot;
  795.  
  796.   while (IFFpart) {
  797.     struct IFFchunk *actIFFpart = IFFpart;
  798.     int indentSpace = iterVal;
  799.     
  800.     while (indentSpace-- > 0) {
  801.       oprintf("  ");
  802.     }
  803.     oprintf("%4s %d bytes\n", (char *)&actIFFpart->type, actIFFpart->size);
  804.  
  805.     switch (actIFFpart->type) {
  806.       /*
  807.        * only toplevel-processing (iter 0)
  808.        */
  809.       case ID_TDDD:
  810.       /*
  811.        * only toplevel-processing (iter 1)
  812.        */
  813.       case ID_OBJ:
  814.         pIFFtopMap(bspMem, actIFFpart->iter, iterVal + 1);
  815.         break;
  816.       /*
  817.        * only toplevel-processing (iter 2)
  818.        */
  819.       case ID_DESC:
  820.         if(iterVal == 2)
  821.           /* the dummy-axis to save the hierarchie to disk */
  822.           pIFFtopMap(bspMem, actIFFpart->iter, iterVal + 1);
  823.         else {      
  824.           if(actIFFpart->iter) {
  825.             struct IFFchunk *Brushes = actIFFpart->iter;
  826.             struct entity *thisEntity;
  827.             
  828.         if (bspMem->nummapentities == bspMem->max_nummapentities)
  829.           ExpandClusters(bspMem, MAP_ENTITIES);
  830.         thisEntity = &bspMem->mapentities[bspMem->nummapentities];
  831.         bspMem->nummapentities++;
  832.  
  833.             while(Brushes) {
  834.               if(Brushes->type == ID_NAME) {
  835.                 thisEntity->classname = (char *)tmalloc(strlen(Brushes->data) + 1);
  836.                 strlwrcpy(thisEntity->classname, Brushes->data);
  837.               }
  838.               else if(Brushes->type == ID_INT1) {
  839.                 struct int1 *inten = (struct int1 *)Brushes->data;
  840.                 thisEntity->light = (unsigned char)rint((fract2float(inten->intensity.x) + 
  841.                                           fract2float(inten->intensity.y) + 
  842.                                          fract2float(inten->intensity.z)) / 3);
  843.               }
  844.               else if(Brushes->type == ID_SHP2) {
  845.                 struct shap *shape = (struct shap *)Brushes->data;
  846.                 if((shape->lamp & LP2_TYPE) != LP2_NOLAM)
  847.                   thisEntity->style = 1;
  848.               }
  849.               else if(Brushes->type == ID_POSI) {
  850.                 struct posi *origin = (struct posi *)Brushes->data;
  851.                 thisEntity->origin[0] = fract2float(origin->position.x);
  852.                 thisEntity->origin[1] = fract2float(origin->position.y);
  853.                 thisEntity->origin[2] = fract2float(origin->position.z);
  854.               }
  855.               else if(Brushes->type == ID_TXT4) {
  856.                 struct texture4 *brushtex = (struct texture4 *)Brushes->data;
  857.                 struct epair *lastString;
  858.                 struct epair *actString = (struct epair *)tmalloc(sizeof(struct epair));
  859.                 
  860.                 actString->next = 0;
  861.                 actString->key = (char *)tmalloc(brushtex->length + 1);
  862.                 strncpy(actString->key, brushtex->name, brushtex->length);
  863.                 actString->key[brushtex->length] = 0;
  864.                 actString->value = (char *)tmalloc(strlen(brushtex->label) +1);
  865.                 strcpy(actString->value, brushtex->label);
  866.                 
  867.         if((lastString = thisEntity->epairs)) {
  868.           while(lastString->next)
  869.             lastString = lastString->next;
  870.           lastString->next = actString;
  871.         }
  872.         else
  873.           thisEntity->epairs = actString;
  874.               }
  875.               else if(Brushes->type == ID_DESC) {
  876.                 /*
  877.                  * after this we get no datas any more
  878.                  */
  879.                 if(Brushes->iter)
  880.                   pIFFtopBrushes(bspMem, Brushes->iter, iterVal + 1, thisEntity);
  881.               }
  882.               Brushes = Brushes->next;
  883.             }
  884.  
  885.         /*
  886.          * for all 
  887.          */
  888.         if (VectorZero(thisEntity->origin))
  889.           GetVectorForKey(thisEntity, "origin", thisEntity->origin);
  890.         if(!thisEntity->classname)
  891.           thisEntity->classname = ValueForKey(thisEntity, "classname");
  892.         thisEntity->target = ValueForKey(thisEntity, "target");
  893.         thisEntity->targetname = ValueForKey(thisEntity, "targetname");
  894.  
  895.         /*
  896.          * special for qbsp+light+vis in one part 
  897.          */
  898.         if (bspMem->mapOptions & MAP_LOADLIGHTS) {
  899.           if (!(thisEntity->light = FloatForKeyN(thisEntity, "light")))
  900.             if (!(thisEntity->light = FloatForKey(thisEntity, "_light")))
  901.               if (!thisEntity->light)
  902.             thisEntity->light = MAX_MAPLIGHTLEVEL;
  903.           if (!(thisEntity->style = FloatForKey(thisEntity, "style")))
  904.             if (!(thisEntity->style = FloatForKey(thisEntity, "_style")))
  905.           if (!thisEntity->style)
  906.             thisEntity->style = 0;
  907.           if (!thisEntity->angle)
  908.             thisEntity->angle = FloatForKey(thisEntity, "angle");
  909.  
  910.           if (strcmp(thisEntity->classname, "light")) {
  911.             if (!thisEntity->light)
  912.           thisEntity->light = DEFAULTLIGHTLEVEL;
  913.  
  914.             if (thisEntity->targetname[0] && !thisEntity->style) {
  915.           char s[256];
  916.  
  917.           thisEntity->style = LightStyleForTargetname(thisEntity->targetname, TRUE);
  918.           sprintf(s, "%i", thisEntity->style);
  919.           SetKeyValue(thisEntity, "style", s);
  920.             }
  921.           }
  922.         }
  923.           }
  924.         }
  925.         break;
  926.       default:
  927.         break;
  928.     }
  929.     IFFpart = IFFpart->next;
  930.     tfree(actIFFpart->data);
  931.     tfree(actIFFpart);
  932.   }
  933. }
  934.  
  935. /*
  936.  the rules:
  937.  
  938.  -the hierarchy:
  939.  
  940.  DESC "world/axis/root" (axis)
  941.   -> acts as global group-manager to save all subhierarchies
  942.    DESC "worldspawn" (axis)
  943.     -> all subdesc's desribes the brushes (objects grouped to axis "worldspawn")
  944.     -> all subdesc's texture info must contain the name of the texture to use and
  945.        the alignment/positioning must be valid
  946.    DESC "info_player_start" (axis)
  947.     -> the axis position describes the players origin
  948.    DESC "standard quake"
  949.     -> will be searched for information
  950.        (eg. DESC "light" (axis with light) is the standard entity "light", parameters
  951.        are parsed out of the axis-informations)
  952.     -> axis that are groupt to a non-worldspawn-entity and that have no brushes
  953.        will beinterpreted as movement-points (?)
  954.     -> the texture-list of an entity will be parsed for key-values (standard-quake
  955.        like "target")
  956.  
  957.  restriction: 
  958.  
  959.   dont make objects, that are not convex
  960.   calculation of clockwise point-order goes via middlepoint of object
  961.   
  962.  */
  963.  
  964. /*
  965.  * ================
  966.  * SaveTDDDFile
  967.  * ================
  968.  */
  969. bool SaveTDDDFile(__memBase, FILE * outFile)
  970. {
  971.   struct entity *ent;
  972.   struct epair *ep;
  973.   struct mbrush *b;
  974.   struct mface *f;
  975.   int i;
  976.   struct dmiptexlump_t *head_miptex = (struct dmiptexlump_t *)bspMem->dtexdata;
  977.   struct texinfo *texinfo;
  978.   struct mipmap *miptex;
  979.   int lastTDDD = 0;
  980.   int lastObj = 0;
  981.   int lastWorld = 0;
  982.   int lastRoot = 0;
  983.   int lastDesc = 0;
  984.  
  985.  /*
  986.   hierarchy:
  987.   
  988.     TDDD
  989.       OBJ
  990.         DESC     worldaxis
  991.         | DESC      worldspawn
  992.         | | DESC   model1
  993.         | | +-TOBJ
  994.         | | DESC   model2
  995.         | | +-TOBJ
  996.         | | ...
  997.         | +-TOBJ
  998.         | DESC      light
  999.         | ...
  1000.         +-TOBJ
  1001.   */
  1002.  
  1003.   SetForm(outFile, &lastTDDD, "TDDD");
  1004.   SetRoot(outFile, &lastObj, "OBJ ");
  1005.  
  1006.   SetRoot(outFile, &lastWorld, "DESC");
  1007.   SetClassName(outFile, "worldaxis");
  1008.   SetOtherDefaults(outFile, 0);
  1009.   VerRoot(outFile, &lastWorld, "DESC");
  1010.  
  1011.   /* set worldspawn as root of all the other models */
  1012.   SetRoot(outFile, &lastRoot, "DESC");
  1013.   for (i = 0, ent = bspMem->mapentities; i < bspMem->nummapentities; i++, ent++)
  1014.     if(!strcmp(ent->classname, "worldspawn"))
  1015.       break;
  1016.  
  1017.   if(i == bspMem->nummapentities) {
  1018.     eprintf("SaveTDDDFile: worldspawn not found!\n");
  1019.     return FALSE;
  1020.   }
  1021.  
  1022.   SetClassName(outFile, ent->classname);
  1023.   for (ep = ent->epairs; ep; ep = ep->next)
  1024.     if (strcmp(ep->key, "model"))
  1025.       SetEntity(outFile, ep->key, ep->value);
  1026.   for (b = ent->brushes; b; b = b->next) {
  1027.     for (f = b->faces; f; f = f->next) {
  1028.       texinfo = &bspMem->texinfo[f->texinfo];
  1029.       miptex = (struct mipmap *)((((unsigned char *)bspMem->dtexdata)) + (head_miptex->dataofs[texinfo->miptex]));
  1030.       SaveFace(f->p0, f->p1, f->p2, miptex->name);
  1031.     }
  1032.   }
  1033.   SetPoints(outFile);
  1034.   SetEdges(outFile);
  1035.   SetFaces(outFile);
  1036.   SetBrushes(outFile);
  1037.   SetOtherDefaults(outFile, ent);
  1038.   VerRoot(outFile, &lastRoot, "DESC");
  1039.  
  1040.   for (i = 0, ent = bspMem->mapentities; i < bspMem->nummapentities; i++, ent++) {
  1041.     int model = 0;
  1042.   
  1043.     for (ep = ent->epairs; ep; ep = ep->next) {
  1044.       if (!strcmp(ep->key, "model")) {
  1045.         model = 1;
  1046.         break;
  1047.       }
  1048.     }
  1049.  
  1050.     if(model && strcmp(ent->classname, "worldspawn")) {
  1051.       SetRoot(outFile, &lastDesc, "DESC");
  1052.       SetClassName(outFile, ent->classname);
  1053.       for (ep = ent->epairs; ep; ep = ep->next)
  1054.         if (strcmp(ep->key, "model"))
  1055.           SetEntity(outFile, ep->key, ep->value);
  1056.       for (b = ent->brushes; b; b = b->next) {
  1057.         for (f = b->faces; f; f = f->next) {
  1058.           texinfo = &bspMem->texinfo[f->texinfo];
  1059.           miptex = (struct mipmap *)((((unsigned char *)bspMem->dtexdata)) + (head_miptex->dataofs[texinfo->miptex]));
  1060.           SaveFace(f->p0, f->p1, f->p2, miptex->name);
  1061.         }
  1062.       }
  1063.       SetPoints(outFile);
  1064.       SetEdges(outFile);
  1065.       SetFaces(outFile);
  1066.       SetBrushes(outFile);
  1067.       SetOtherDefaults(outFile, ent);
  1068.       VerRoot(outFile, &lastDesc, "DESC");
  1069.       SetEndM(outFile, "TOBJ");
  1070.     }
  1071.   }
  1072.   SetEndM(outFile, "TOBJ");
  1073.  
  1074.   for (i = 0, ent = bspMem->mapentities; i < bspMem->nummapentities; i++, ent++) {
  1075.     int model = 0;
  1076.   
  1077.     for (ep = ent->epairs; ep; ep = ep->next) {
  1078.       if (!strcmp(ep->key, "model")) {
  1079.         model = 1;
  1080.         break;
  1081.       }
  1082.     }
  1083.  
  1084.     if(!model && strcmp(ent->classname, "worldspawn")) {
  1085.       SetRoot(outFile, &lastDesc, "DESC");
  1086.       SetClassName(outFile, ent->classname);
  1087.       for (ep = ent->epairs; ep; ep = ep->next)
  1088.         if (strcmp(ep->key, "model"))
  1089.           SetEntity(outFile, ep->key, ep->value);
  1090.       for (b = ent->brushes; b; b = b->next) {
  1091.         for (f = b->faces; f; f = f->next) {
  1092.           texinfo = &bspMem->texinfo[f->texinfo];
  1093.           miptex = (struct mipmap *)((((unsigned char *)bspMem->dtexdata)) + (head_miptex->dataofs[texinfo->miptex]));
  1094.           SaveFace(f->p0, f->p1, f->p2, miptex->name);
  1095.         }
  1096.       }
  1097.       SetPoints(outFile);
  1098.       SetEdges(outFile);
  1099.       SetFaces(outFile);
  1100.       SetBrushes(outFile);
  1101.       SetOtherDefaults(outFile, ent);
  1102.       VerRoot(outFile, &lastDesc, "DESC");
  1103.       SetEndM(outFile, "TOBJ");
  1104.     }
  1105.   }
  1106.   SetEndM(outFile, "TOBJ");
  1107.   VerRoot(outFile, &lastObj, "OBJ ");
  1108.   VerRoot(outFile, &lastTDDD, "TDDD");
  1109.   
  1110.   mprintf("----- SaveTDDDFile -------\n");
  1111.   mprintf("%5i points\n", TDDDnumpoints);
  1112.   mprintf("%5i edges\n", TDDDnumedges);
  1113.   mprintf("%5i faces\n", TDDDnumfaces);
  1114.   mprintf("%5i groups\n", TDDDnumgroups);
  1115.   mprintf("%5i objects\n", TDDDnumobjects);
  1116.  
  1117.   return TRUE;
  1118. }
  1119.  
  1120. /*
  1121.  * ================
  1122.  * LoadTDDDFile
  1123.  * ================
  1124.  */
  1125. bool LoadTDDDFile(__memBase, char *tdddBuf)
  1126. {
  1127.   struct IFFheader IFFfile = {0, 0, 0};
  1128.   struct IFFchunk *IFFroot = (struct IFFchunk *)tmalloc(sizeof(struct IFFchunk));
  1129.   
  1130.   memcpy(&IFFfile, tdddBuf, 12);
  1131.   tdddBuf += 12;
  1132.   IFFroot->type = IFFfile.type;
  1133.   IFFroot->size = IFFfile.size - 4;
  1134.   IFFroot->next = 0;
  1135.   IFFroot->iter = 0;
  1136.   IFFroot->data = 0;
  1137.   memIFFtopIFF(tdddBuf, IFFroot);
  1138.   pIFFtopMap(bspMem, IFFroot, 0);
  1139.   MatchTargets(bspMem);
  1140.  
  1141.   mprintf("----- LoadTDDDFile -------\n");
  1142.   mprintf("%5i brushes\n", nummapbrushes);
  1143.   mprintf("%5i entities\n", bspMem->nummapentities);
  1144.   mprintf("%5i miptex\n", bspMem->nummaptexstrings);
  1145.   mprintf("%5i texinfo\n", bspMem->numtexinfo);
  1146.  
  1147.   return TRUE;
  1148. }
  1149.